package com.net.xpay.core.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AccDetailModel;
import com.alipay.api.response.AlipayFundBatchCreateResponse;
import com.alipay.api.response.AlipayFundBatchDetailQueryResponse;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.net.xpay.common.domain.User;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.common.annotation.WriteTransactional;
import com.net.common.concurrent.ThreadUtil;
import com.net.common.exception.BusinessException;
import com.net.common.util.PhoneUtil;
import com.net.common.util.StreamUtil;
import com.net.xpay.alipay.PoseidonAlipayClient;
import com.net.xpay.alipay.enums.IdentityType;
import com.net.xpay.alipay.model.TransOrderModel;
import com.net.xpay.core.domain.AlipayUser;
import com.net.xpay.core.domain.PayTrans;
import com.net.xpay.core.enums.AlipayUserStatus;
import com.net.xpay.core.enums.PayTransStatus;
import com.net.xpay.core.manager.AlipayUserManager;
import com.net.xpay.core.model.AlipayAuthModel;
import com.net.xpay.core.service.AlipayLogonIdAuthService;
import com.net.xpay.core.utils.EmailUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;

/**
 * 2020/6/28 10:58

 */
@Slf4j
@Service
@WriteTransactional
public class AlipayLogonIdServiceImpl implements AlipayLogonIdAuthService {

    private static final long PAY_BATCH_MAX_COUNT = 1000L;

    @Autowired
    private PoseidonAlipayClient xpayAlipayClient;

    @Autowired
    private AlipayUserManager alipayUserManager;

    @Override
    public List<PayTrans> authAlipayLogonId(User user, String alipayNickName, List<AlipayAuthModel> accounts) {
        String importBatchNo = "CHECK_" + user.getId() + "_" + System.currentTimeMillis() + ThreadLocalRandom.current().nextInt(10000);
        List<PayTrans> payTrans = checkPayModel(importBatchNo, accounts, user);

        AlipayUser alipayUser;
        if (!Strings.isNullOrEmpty(alipayNickName)) {
            alipayUser = alipayUserManager.findByAlipayNickName(user.getId(), alipayNickName);
            if (alipayUser == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "付款方支付宝账号不存在");
            }
        } else {
            if (user.getAlipayUserId() == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请先绑定支付宝账号");
            }
            alipayUser = alipayUserManager.getById(user.getAlipayUserId());
        }

        if (alipayUser == null || alipayUser.getStatus() != AlipayUserStatus.YES) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "你的支付宝账号尚未签约，请先签约后再打款");
        }

//        if (alipayUser.getExpiresIn().isBefore(LocalDateTime.now())) {
//            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "支付宝账号签约已过期，请重新签约");
//        }

        //创建支付宝批量打款订单
        alipayFundBatchCreate(importBatchNo, payTrans, alipayUser);

        //查询结果
        try {
            Map<String/*outBizNo*/, PayTrans> payTransMap = StreamUtil.toMap(payTrans, PayTrans::getOutBizNo);
            List<PayTrans> list = Lists.newArrayList();

            ThreadUtil.safeSleep(1000L, "");
            AlipayFundBatchDetailQueryResponse response = allDetailQuery(alipayUser.getId(), importBatchNo);
            long queryCount = 0L;
            while (queryCount < 10L) {
                if (CollectionUtils.isEmpty(response.getAccDetailList())) {
                    ThreadUtil.safeSleep(1000L, "");
                    response = allDetailQuery(alipayUser.getId(), importBatchNo);
                    queryCount++;
                } else {
                    break;
                }
            }

            for (AccDetailModel accDetail : response.getAccDetailList()) {
                PayTrans payTran = payTransMap.get(accDetail.getOutBizNo());
                PayTransStatus status = PayTransStatus.of(accDetail.getStatus());
                payTran.setDetailId(accDetail.getDetailId());
                payTran.setErrorCode(accDetail.getErrorCode());
                payTran.setErrorMsg(accDetail.getErrorMsg());
                payTran.setStatus(status);
                list.add(payTran);
            }

            return list;

        } catch (AlipayApiException e) {
            log.error("authAlipayLogonId error|id={}", importBatchNo, e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "检测失败");
        }

    }

    private AlipayFundBatchDetailQueryResponse allDetailQuery(Long alipayUserId, String outBatchNo) throws AlipayApiException {
        AlipayFundBatchDetailQueryResponse toReturnResponse = detailQuery(alipayUserId, outBatchNo, 1L);
        Long totalPageCount = toReturnResponse.getTotalPageCount();
        Long pageNum = 1L;
        while (pageNum <= totalPageCount) {
            pageNum++;
            if (pageNum <= totalPageCount) {
                AlipayFundBatchDetailQueryResponse response = detailQuery(alipayUserId, outBatchNo, pageNum);
                toReturnResponse.getAccDetailList().addAll(response.getAccDetailList());
            }
        }
        return toReturnResponse;
    }

    private AlipayFundBatchDetailQueryResponse detailQuery(long alipayUserId, String outBatchId, long pageNum) throws AlipayApiException {
        AlipayUser alipayUser = alipayUserManager.getById(alipayUserId);
        return xpayAlipayClient.alipayFundBatchDetailQuery(alipayUser.getAuthToken(), outBatchId, pageNum);
    }

    private void alipayFundBatchCreate(String importBatchNo, List<PayTrans> payTrans, AlipayUser alipayUser) {
        TransOrderModel transOrderModel = buildTransOrderModel(importBatchNo, payTrans);
        AlipayFundBatchCreateResponse response;
        try {
            response = xpayAlipayClient.alipayFundBatchCreate(alipayUser.getAuthToken(), transOrderModel);
        } catch (AlipayApiException e) {
            log.warn("alipayFundBatchCreate error|id={}", importBatchNo, e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "检测失败" );
        }

        if (!response.isSuccess()) {
            log.warn("alipayFundBatchCreate failed importBatchNo={}|errorMsg={}", importBatchNo,  response.getSubMsg() + "|" + response.getMsg());
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "检测失败");
        }
    }

    private TransOrderModel buildTransOrderModel(String importBatchNo, List<PayTrans> payTrans) {
        Function<PayTrans, BigDecimal> sum = ins -> new BigDecimal(ins.getTransAmount());

        TransOrderModel transOrderModel = TransOrderModel.getInstance();
        transOrderModel.setOutBatchNo(importBatchNo);
        transOrderModel.setTotalTransAmount(StreamUtil.sum(payTrans, sum).toString());
        transOrderModel.setTotalCount(String.valueOf(payTrans.size()));
        transOrderModel.setProductCode("BATCH_API_TO_ACC");
        transOrderModel.setBizScene("MESSAGE_BATCH_PAY");
        transOrderModel.setOrderTitle("转账");
        transOrderModel.setTimeExpire(null);
        transOrderModel.setRemark(null);
        List<TransOrderModel.TransOrderDetail> transOrderDetails = Lists.newArrayList();
        for (PayTrans record : payTrans) {
            TransOrderModel.TransOrderDetail detail = TransOrderModel.TransOrderDetail.getInstance();
            detail.setOutBizNo(record.getImportBizNo());
            detail.setTransAmount(record.getTransAmount());
            detail.setRemark(record.getRemark());

            TransOrderModel.PayeeInfo payeeInfo = TransOrderModel.PayeeInfo.getInstance();
            payeeInfo.setIdentity(record.getIdentity());
            payeeInfo.setIdentityType(record.getIdentityType());
            payeeInfo.setName(record.getName());

            detail.setPayeeInfo(payeeInfo);

            transOrderDetails.add(detail);
        }
        transOrderModel.setTransOrderList(transOrderDetails);
        return transOrderModel;
    }

    private List<PayTrans> checkPayModel(String importBatchNo, List<AlipayAuthModel> payTransModelList, User merchant) {
        if (CollectionUtils.isEmpty(payTransModelList)) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "至少检测一个账号");
        }
        if (payTransModelList.size() > PAY_BATCH_MAX_COUNT) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "一次检测不能超过" + PAY_BATCH_MAX_COUNT + "个");
        }

        List<PayTrans> payTrans = Lists.newArrayList();
        StringBuilder errMessage = new StringBuilder();

        for (int i = 0; i < payTransModelList.size(); i++) {
            AlipayAuthModel row = payTransModelList.get(i);
            String alipayNo = row.getIdentity();
            String name = row.getName();
            String identityType = row.getIdentityType();

            //买家昵称 和 支付宝账号&真实姓名 二选一必填一项
            if ((Strings.isNullOrEmpty(alipayNo) || Strings.isNullOrEmpty(name))) {
                errMessage.append(" (第").append(i + 1).append("条:").append("支付宝账号&真实姓名必填");
                continue;
            }

            PayTrans instance = PayTrans.getInstance();
            instance.setUserId(merchant.getId());
            instance.setPartnerId(merchant.getPartnerId());
            instance.setMobile(merchant.getMobile());
            instance.setPayTransBatchId(null);
            instance.setImportBatchNo(importBatchNo);

            instance.setOutBizNo(merchant.getId() + "_" + System.currentTimeMillis() + "_" + i);
            instance.setImportBizNo(merchant.getId() + "_" + System.currentTimeMillis() + "_" + i);
            instance.setTransAmount("1");
            instance.setRemark("转账");
            instance.setName(name);
            instance.setStatus(PayTransStatus.IMPORTED);
            instance.setVersion(0L);

            //支付宝账号优先 可以转的金额更大
            if (!Strings.isNullOrEmpty(alipayNo) && !Strings.isNullOrEmpty(name)) {
                if (IdentityType.ALIPAY_LOGON_ID.getValue().equals(identityType)) {
                    if (alipayNo.contains(" ")) {
                        errMessage.append(" (第").append(i + 1).append("条:").append("支付宝账号不能有空格) ");
                        continue;
                    }
                    if (!alipayNo.contains("@")) {
                        if (!PhoneUtil.isEffectiveMobile(alipayNo)) {
                            errMessage.append(" (第").append(i + 1).append("条:").append("支付宝账号格式错误) ");
                            continue;
                        }
                    } else {
                        if (!EmailUtil.checkEmail(alipayNo)) {
                            errMessage.append(" (第").append(i + 1 + 3).append("行:").append("支付宝账号格式错误) ");
                        }
                    }
                }
            }
            instance.setIdentity(alipayNo);
            instance.setIdentityType(identityType);
            payTrans.add(instance);
        }

        if (!Strings.isNullOrEmpty(errMessage.toString())) {
            throw new BusinessException(PoseidonErrorCode.ALIPAY_LOGIN_ID_ERROR, errMessage.toString());
        }

        if (CollectionUtils.isEmpty(payTrans)) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "至少上传一个支付宝账号");
        }

        return payTrans;
    }

}
